package dataTypes;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 
 * @author Felix Schliephacke
 * 
 */
public final class FieldImpl implements Field<Integer> {

	private static final long serialVersionUID = 8170196879522306601L;

	public static Field<Integer> getInstance(Field<Integer> field) {
		return new FieldImpl(field);
	}

	public static Field<Integer> getInstance(int squareSize)
			throws IllegalArgumentException {
		if (squareSize <= 0) {
			throw new IllegalArgumentException(
					"Argument must be greater than 0.");
		}
		return new FieldImpl(squareSize);
	}

	public static Field<Integer> getInstance(int squareSize, Integer arg) {
		return new FieldImpl(squareSize, arg);
	}

	private transient List<Integer> field;

	private transient int size;

	private transient int squareSize;

	private FieldImpl(Field<Integer> field) {
		this.squareSize = field.getSquareSize();
		this.size = this.squareSize * this.squareSize;
		this.field = new ArrayList<Integer>();
		for (int i = 0; i < field.size(); i++) {
			this.field.add(field.get(i));
		}
	}

	private FieldImpl(int size) {
		this.squareSize = size;
		this.size = this.squareSize * this.squareSize;
		this.field = new ArrayList<Integer>(this.size);
		this.reset();
	}

	private FieldImpl(int squareSize, Integer arg) {
		this.squareSize = squareSize;
		this.size = this.squareSize * this.squareSize;
		this.field = new ArrayList<Integer>(this.squareSize);
		if (arg == null) {
			this.reset();
		} else {
			this.field.add(arg);
		}
	}

	@Override
	public Field<Integer> clone() {
		return FieldImpl.getInstance(this);
	}

	@Override
	public boolean contains(Integer arg) {
		return this.field.contains(arg);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof FieldImpl))
			return false;
		FieldImpl other = (FieldImpl) obj;
		if (field == null) {
			if (other.field != null)
				return false;
		} else if (!field.equals(other.field))
			return false;
		if (size != other.size)
			return false;
		return true;
	}

	@Override
	public Integer get(int index) {
		return this.field.get(index);
	}

	@Override
	public int getSquareSize() {
		return this.squareSize;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((field == null) ? 0 : field.hashCode());
		result = prime * result + size;
		return result;
	}

	@Override
	public Iterator<Integer> iterator() {
		return this.field.iterator();
	}

	@Override
	public boolean remove(Integer arg) {
		return this.field.remove(arg);
	}

	@Override
	public void reset() {
		this.field.clear();
		for (int i = 1; i <= this.size; i++) {
			this.field.add(i);
		}
	}

	@Override
	public void set(Integer content) {
		this.field.clear();
		this.field.add(content);
	}

	@Override
	public int size() {
		return this.field.size();
	}

	@Override
	public String toString() {
		return this.field.toString();
	}

	private void readObject(ObjectInputStream s) throws IOException,
			ClassNotFoundException {
		s.defaultReadObject();
		this.squareSize = s.readInt();
		if (this.squareSize <= 0) {
			throw new IllegalStateException("Serialized Field is corrupted.");
		}
		this.size = this.squareSize * this.squareSize;
		int elements = s.readInt();
		this.field = new ArrayList<Integer>(this.size);
		for (int i = 0; i < elements; i++) {
			this.field.add(s.readInt());
		}
	}

	private void writeObject(ObjectOutputStream s) throws IOException {
		s.defaultWriteObject();
		s.writeInt(this.squareSize);
		s.writeInt(this.size());
		for (Integer temp : this.field) {
			s.writeInt(temp);
		}
	}

	// @Override
	// protected void finalize() {
	// this.field = null;
	// }
}
